package session

import (
	"time"
	"sync"
	"io"
	"strconv"
	"encoding/base64"
	"crypto/rand"
)

var sessionManage = SessionManage{
	Lock:        sync.RWMutex{},
	MaxLifeTime: -1, //s
	Sessions:    make(map[string]*Session),
}

func init() {
	if sessionManage.MaxLifeTime > 0 {
		go sessionManage.GC()
	}
}

/*Session会话管理*/
type SessionManage struct {
	CookieName  string              //客户端cookie名称
	Lock        sync.RWMutex        //互斥(保证线程安全)
	MaxLifeTime int64               //垃圾回收时间
	Sessions    map[string]*Session //保存session的指针[sessionID] = session
}

//GC回收
func (sm *SessionManage) GC() {
	sm.Lock.Lock()
	defer sm.Lock.Unlock()
	for sessionID, session := range sm.Sessions {
		//删除超过时限的session
		if session.LastTimeAccessed.Unix()+sm.MaxLifeTime < time.Now().Unix() {
			delete(sm.Sessions, sessionID)
		}
	}
	//定时回收
	time.AfterFunc(time.Duration(sm.MaxLifeTime)*time.Second, func() { sm.GC() })
}

func (sm *SessionManage) GetSession(sessionID string) (*Session, bool) {
	sm.Lock.Lock()
	defer sm.Lock.Unlock()
	session, ok := sm.Sessions[sessionID]
	return session, ok
}
func LoginOut(userID string) {
	sessionManage.Lock.Lock()
	defer sessionManage.Lock.Unlock()
	for sessionID, session := range sessionManage.Sessions {
		//删除这个userId的所有session
		if session.Values["user_id"] == userID {
			delete(sessionManage.Sessions, sessionID)
		}
	}
}

/*会话*/
type Session struct {
	SessionID        string                 `json:"session_id"`         //唯一id
	LastTimeAccessed time.Time              `json:"last_time_accessed"` //最后访问时间
	Values           map[string]interface{} `json:"values"`             //其它对应值(保存用户所对应的一些值，比如用户权限之类)
	MaxLifeTime      int64                  `json:"max_life_time"`      //垃圾回收时间
}

func NewSession() *Session {
	session := Session{
		SessionID:        createSessionID(),
		LastTimeAccessed: time.Now(),
		Values:           make(map[string]interface{}),
	}
	sessionManage.Sessions[session.SessionID] = &session
	return &session
}
func (session *Session) SetValue(key string, v interface{}) {
	session.Values[key] = v
}
func (session *Session) UpLastTimeAccessed() (*Session) {
	session.LastTimeAccessed = time.Now()
	return session
}
func (session *Session) GetValue(key string) (interface{}, bool) {
	v, ok := session.Values[key]
	return v, ok
}
func (session *Session) DeleteValue(keys ...string) {
	for _, v := range keys {
		delete(session.Values, v)
	}

}
func GetSession(sessionID string) (*Session, bool) {
	return sessionManage.GetSession(sessionID)
}

//创建唯一ID
func createSessionID() string {
	b := make([]byte, 32)
	if _, err := io.ReadFull(rand.Reader, b); err != nil {
		nano := time.Now().UnixNano() //微秒
		return strconv.FormatInt(nano, 10)
	}
	return base64.URLEncoding.EncodeToString(b)
}
